#ifndef LINKLIST_H
#define LINKLIST_H

#include "List.h"
#include "Exception.h"

namespace StructLib
{
    template <typename T>
    class LinkList : public List<T>
    {
    protected:
        struct Node : public Object
        {
            T value;
            Node *next; 
        };
        
        mutable struct  : public Object
        {
            char reserved[sizeof(T)];
            Node *next;
        }m_header;
        int m_length;

        Node *Position(int i) const
        {
            Node *ret = reinterpret_cast<Node*>(&m_header);

            for (int p = 0; p < i; p++)
            {
                ret = ret->next;
            }

            return ret;
        }

    public:
        LinkList()
        {
            m_header.next = NULL;
            m_length = 0;
        }

        bool Insert(const T& e)
        {
            return Insert(m_length, e);
        }

        bool Insert(int i, const T& e)
        {
            bool ret = ((0 <= i) && (i <= m_length));

            if (ret)
            {
                Node *node = new Node();

                if (node != NULL)
                {
                    Node *current = Position(i);

                    node->value = e;
                    node->next = current->next;
                    current->next = node;

                    m_length++;
                }
                else
                {
                    THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create");
                }
            }

            return ret;
        }

        bool Remove(int i)
        {
            bool ret = ((0 <= i) && (i <= m_length));

            if (ret)
            {
                Node *current = Position(i);
                Node *toDel = current->next;

                current->next = toDel->next;

                delete toDel;

                m_length--;
            }

            return ret;
        }

        bool Set(int i, const T&e)
        {
            bool ret = ((0 <= i) && (i <= m_length));

            if (ret)
            {
                Node *current = Position(i);
                current->next->value = e;
            }

            return ret;
        }

        bool Get(int i, T&e) const
        {
            bool ret = ((0 <= i) && (i <= m_length));

            if (ret)
            {
                Node *current = Position(i);
                e = current->next->value;
            }

            return ret;
        }

        T Get(int i) const
        {
            T ret;

            if ( Get(i, ret) )
            {
                return ret;
            }
            else
            {
                THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is invalid...");
            }
            
        }

        int Length() const
        {
            return m_length;
        }

        void Clear()
        {
            while ( m_header.next )
            {
                Node *toDel = m_header.next;

                m_header.next = toDel->next;

                delete toDel;
            }
            
            m_length = 0;
        }

        ~LinkList()
        {
            Clear();
        }
    };


} // namespace StructLib

#endif // !LINKLIST_H